package com.example.shuiyin.service.impl;

import com.example.shuiyin.entity.UserQuota;
import com.example.shuiyin.service.QuotaService;
import com.example.shuiyin.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.util.concurrent.TimeUnit;
import com.example.shuiyin.entity.User;
import com.example.shuiyin.exception.AppException;
import com.example.shuiyin.exception.ErrorCode;
import com.example.shuiyin.dto.UserQuotaInfo;
import com.example.shuiyin.mapper.UserQuotaMapper;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.shuiyin.entity.FileInfo;
import com.example.shuiyin.mapper.FileInfoMapper;

@Service
@Slf4j
public class QuotaServiceImpl implements QuotaService {

    private final UserQuotaMapper userQuotaMapper;
    private final RedisTemplate<String, Object> redisTemplate;
    private final FileInfoMapper fileInfoMapper;
    
    @Autowired
    private UserService userService;
    
    private static final String QUOTA_KEY = "user:quota:";
    private static final long QUOTA_CACHE_TIME = 30 * 60; // 30分钟
    
    public QuotaServiceImpl(UserQuotaMapper userQuotaMapper, 
                           RedisTemplate<String, Object> redisTemplate,
                           FileInfoMapper fileInfoMapper) {
        this.userQuotaMapper = userQuotaMapper;
        this.redisTemplate = redisTemplate;
        this.fileInfoMapper = fileInfoMapper;
    }
    
    // 检查Redis是否可用
    private boolean isRedisAvailable() {
        try {
            redisTemplate.getConnectionFactory().getConnection().ping();
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    @Cacheable(value = "quotaCache", key = "#userId", unless = "#result == null")
    public UserQuotaInfo getUserQuotaInfo(Long userId) {
        UserQuota quota = findOrCreateQuota(userId);
        
        // 检查是否需要重置配额
        checkAndResetQuota(quota);
        
        User user = userService.getUserById(userId);
        int userLevel = user.getUserLevel() != null ? user.getUserLevel() : 1;
        
        return UserQuotaInfo.builder()
                .userLevel(userLevel)
                .maxStorageSize(quota.getMaxStorageSize())
                .usedStorageSize(quota.getUsedStorageSize())
                .maxProcessingCount(quota.getMaxProcessingCount())
                .usedProcessingCount(quota.getUsedProcessingCount())
                .resetDate(quota.getResetDate())
                .lastUsedTime(quota.getLastUsedTime())
                .build();
    }
    
    @Override
    public boolean hasProcessingQuota(Long userId) {
        // 尝试从Redis获取
        if (isRedisAvailable()) {
            try {
                String key = QUOTA_KEY + userId;
                UserQuotaInfo cachedQuota = (UserQuotaInfo) redisTemplate.opsForValue().get(key);
                
                if (cachedQuota != null) {
                    return cachedQuota.getUsedProcessingCount() < cachedQuota.getMaxProcessingCount();
                }
            } catch (Exception e) {
                log.warn("从Redis获取配额失败: {}", e.getMessage());
            }
        }
        
        // 从数据库获取
        UserQuota quota = findOrCreateQuota(userId);
        
        // 检查是否需要重置配额
        checkAndResetQuota(quota);
        
        return quota.getUsedProcessingCount() < quota.getMaxProcessingCount();
    }
    
    @Override
    @Transactional
    @CacheEvict(value = "quotaCache", key = "#userId")
    public void recordProcessingUsage(Long userId) {
        UserQuota quota = findOrCreateQuota(userId);
        
        // 检查是否需要重置配额
        checkAndResetQuota(quota);
        
        if (quota.getUsedProcessingCount() >= quota.getMaxProcessingCount()) {
            throw new AppException("处理配额不足", ErrorCode.QUOTA_EXCEEDED);
        }
        
        quota.setUsedProcessingCount(quota.getUsedProcessingCount() + 1);
        quota.setLastUsedTime(LocalDateTime.now());
        userQuotaMapper.updateById(quota);
        
        // 更新缓存
        updateQuotaCache(userId);
    }
    
    @Override
    @Transactional
    @CacheEvict(value = "quotaCache", key = "#userId")
    public void recordStorageUsage(Long userId, long size) {
        UserQuota quota = findOrCreateQuota(userId);
        
        if (quota.getUsedStorageSize() + size > quota.getMaxStorageSize()) {
            throw new AppException("存储空间不足", ErrorCode.QUOTA_EXCEEDED);
        }
        
        quota.setUsedStorageSize(quota.getUsedStorageSize() + size);
        quota.setLastUsedTime(LocalDateTime.now());
        userQuotaMapper.updateById(quota);
        
        // 更新缓存
        updateQuotaCache(userId);
    }
    
    /**
     * 减少存储配额使用
     */
    @Override
    @Transactional
    @CacheEvict(value = "quotaCache", key = "#userId")
    public void reduceStorageUsage(Long userId, long size) {
        UserQuota quota = findOrCreateQuota(userId);
        
        // 确保使用量不会小于0
        long newSize = Math.max(0, quota.getUsedStorageSize() - size);
        quota.setUsedStorageSize(newSize);
        quota.setLastUsedTime(LocalDateTime.now());
        userQuotaMapper.updateById(quota);
        
        // 更新缓存
        updateQuotaCache(userId);
    }
    
    /**
     * 设置存储配额使用量
     */
    @Override
    @Transactional
    @CacheEvict(value = "quotaCache", key = "#userId")
    public void setStorageUsage(Long userId, long size) {
        UserQuota quota = findOrCreateQuota(userId);
        
        if (size > quota.getMaxStorageSize()) {
            log.warn("用户[{}]的存储使用量[{}]超过最大配额[{}]", userId, size, quota.getMaxStorageSize());
        }
        
        quota.setUsedStorageSize(size);
        quota.setLastUsedTime(LocalDateTime.now());
        userQuotaMapper.updateById(quota);
        
        // 更新缓存
        updateQuotaCache(userId);
    }
    
    /**
     * 获取或创建用户配额记录
     */
    private UserQuota findOrCreateQuota(Long userId) {
        UserQuota quota = userQuotaMapper.selectByUserId(userId);
        
        if (quota == null) {
            return createDefaultQuota(userId);
        }
        
        return quota;
    }
    
    /**
     * 创建默认配额
     */
    private UserQuota createDefaultQuota(Long userId) {
        User user = userService.getUserById(userId);
        int userLevel = user.getUserLevel() != null ? user.getUserLevel() : 1;
        
        UserQuota quota = new UserQuota();
        quota.setUserId(userId);
        
        // 基于用户等级设置配额
        setQuotaByUserLevel(quota, userLevel);
        
        quota.setResetDate(getNextMonthFirstDay());
        quota.setCreatedAt(LocalDateTime.now());
        quota.setUpdatedAt(LocalDateTime.now());
        
        userQuotaMapper.insert(quota);
        
        return quota;
    }
    
    // 更新缓存
    private void updateQuotaCache(Long userId) {
        if (isRedisAvailable()) {
            try {
                UserQuotaInfo quota = getUserQuotaInfo(userId);
                redisTemplate.opsForValue().set(QUOTA_KEY + userId, quota, QUOTA_CACHE_TIME, TimeUnit.SECONDS);
            } catch (Exception e) {
                log.warn("更新Redis缓存失败: {}", e.getMessage());
            }
        }
    }
    
    /**
     * 检查并重置配额
     */
    @Transactional
    private void checkAndResetQuota(UserQuota quota) {
        LocalDateTime now = LocalDateTime.now();
        
        // 如果当前日期已经过了重置日期，则重置配额
        if (quota.getResetDate() != null && now.isAfter(quota.getResetDate())) {
            User user = userService.getUserById(quota.getUserId());
            int userLevel = user.getUserLevel() != null ? user.getUserLevel() : 1;
            
            // 重置处理次数配额
            setQuotaByUserLevel(quota, userLevel);
            
            // 设置下一个重置日期
            quota.setResetDate(getNextMonthFirstDay());
            quota.setUpdatedAt(now);
            
            userQuotaMapper.updateById(quota);
            
            log.info("已重置用户[{}]的配额，下次重置时间: {}", quota.getUserId(), quota.getResetDate());
        }
    }
    
    /**
     * 根据用户等级设置配额
     */
    private void setQuotaByUserLevel(UserQuota quota, int userLevel) {
        // 根据用户等级设置不同的配额
        switch (userLevel) {
            case 1: // 普通用户
                quota.setMaxStorageSize(1024L * 1024 * 1024); // 1GB
                quota.setMaxProcessingCount(10);
                break;
            case 2: // VIP用户
                quota.setMaxStorageSize(5 * 1024L * 1024 * 1024); // 5GB
                quota.setMaxProcessingCount(50);
                break;
            case 3: // 高级VIP用户
                quota.setMaxStorageSize(20 * 1024L * 1024 * 1024); // 20GB
                quota.setMaxProcessingCount(200);
                break;
            default: // 其他等级，默认为普通用户配额
                quota.setMaxStorageSize(1024L * 1024 * 1024); // 1GB
                quota.setMaxProcessingCount(10);
                break;
        }
        
        // 设置使用量为0(针对新用户)或保持不变(针对重置配额)
        if (quota.getUsedProcessingCount() == null) {
            quota.setUsedProcessingCount(0);
        }
        
        if (quota.getUsedStorageSize() == null) {
            quota.setUsedStorageSize(0L);
        }
    }
    
    /**
     * 获取下个月第一天
     */
    private LocalDateTime getNextMonthFirstDay() {
        return LocalDateTime.now()
                .plusMonths(1)
                .with(TemporalAdjusters.firstDayOfMonth())
                .with(LocalTime.MIN);
    }
    
    @Override
    public List<Long> getUsersNearQuotaLimit(int threshold) {
        if (threshold < 0 || threshold > 100) {
            throw new IllegalArgumentException("阈值必须在0-100之间");
        }
        
        // 查询所有用户配额
        List<UserQuota> allQuotas = userQuotaMapper.selectList(null);
        
        // 筛选接近上限的用户
        return allQuotas.stream()
                .filter(quota -> {
                    double usagePercent = (quota.getUsedStorageSize() * 100.0) / quota.getMaxStorageSize();
                    return usagePercent >= threshold;
                })
                .map(UserQuota::getUserId)
                .collect(Collectors.toList());
    }
    
    @Override
    public boolean hasStorageQuota(Long userId, long requiredSize) {
        UserQuota quota = findOrCreateQuota(userId);
        return quota.getUsedStorageSize() + requiredSize <= quota.getMaxStorageSize();
    }
    
    @Override
    public long getStorageUsage(Long userId) {
        if (userId == null) {
            throw new AppException("用户ID不能为空", ErrorCode.INVALID_PARAMETER);
        }
        
        // 查询用户活跃文件的总大小
        return getUsedStorageByUser(userId);
    }
    
    @Override
    public long getStorageQuota(Long userId) {
        if (userId == null) {
            throw new AppException("用户ID不能为空", ErrorCode.INVALID_PARAMETER);
        }
        
        // 查询用户配额
        UserQuota quota = userQuotaMapper.selectByUserId(userId);
        if (quota == null) {
            // 如果没有配置，返回默认配额（例如10GB）
            return 10L * 1024 * 1024 * 1024;
        }
        
        return quota.getStorageQuota();
    }
    
    private Long getUsedStorageByUser(Long userId) {
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId)
                .eq("status", "ACTIVE");
        
        return fileInfoMapper.selectList(queryWrapper).stream()
                .mapToLong(FileInfo::getFileSize)
                .sum();
    }
    
    private boolean hasEnoughStorage(UserQuota quota, long fileSize) {
        // 获取当前已使用的存储空间
        long usedSpace = quota.getUsedStorage();
        
        // 获取总配额
        Long maxStorage = quota.getMaxStorage();
        
        // 无限配额
        if (maxStorage == null || maxStorage == -1) {
            return true;
        }
        
        // 检查是否超出配额
        return usedSpace + fileSize <= maxStorage;
    }
    
    // 其他辅助方法...
} 